using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using H2;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using MySettings = Ceiling_Cat.Properties.Settings;

namespace Ceiling_Cat
{
    public partial class MapEditor : Form
    {
        private Main main;
        public MapStream Map;

        private BitmapViewer bitmViewer;

        public MapEditor()
        {
            InitializeComponent();
        }

        public MapEditor(Main _main, string mapPath)
        {
            InitializeComponent();
            probar.ProgressType = DevComponents.DotNetBar.eProgressItemType.Marquee;
            main = _main;
            Map = new MapStream(mapPath, StatusChanged);
            Application.DoEvents();
            Open();
            bitmViewer = new BitmapViewer(Map, MySettings.Default.MainMenu, MySettings.Default.Shared, MySettings.Default.SingleplayerShared);
            Map.Close();
            probar.ProgressType = DevComponents.DotNetBar.eProgressItemType.Standard;
        }

        private void Open()
        {
            LoadHeader();
            LoadIndex();

            lstSIDs.Items.AddRange(Map.StringIDs.ToStringArray());
            lstSIDs.SelectedIndex = 0;

            LoadUnicode();

            StatusChanged("Loading Treeview...");
            trvTags.SuspendLayout();
            trvTags.Nodes.Clear();

            H2.Sections.Tags.TagTable tt = Map.Tags.GetTagTable();
            for (int i = 0; i < tt.Count; i++)
            {
                Application.DoEvents();
                if (!trvTags.Nodes.ContainsKey(tt[i].Class)) trvTags.Nodes.Add(tt[i].Class, tt[i].Class);
                trvTags.Nodes[tt[i].Class].Nodes.Add(tt[i].Class, tt[i].Path);
            }

            trvTags.Enabled = true;
            trvTags.ResumeLayout();

            StatusChanged("Ready.");
        }

        private void StatusChanged(string status)
        {
            lblStatus.Text = status;
        }

        private void trvTags_AfterSelect(object sender, TreeViewEventArgs e)
        {
            RawBar.SubItems.Clear();
            if (e.Node != null && e.Node.Parent != null) //Tag Is Selected
            {
                H2.Sections.TagInfo ti = Map.Tags[e.Node.Parent.Text, e.Node.Text];
                txtTagOffset.TextBox.Text = ti.Offset.ToString();
                txtTagSize.TextBox.Text = ti.Size.ToString();
                txtTagPath.TextBox.Text = e.Node.Text;
                txtTagClass.TextBox.Text = e.Node.Parent.Text;

                switch (e.Node.Parent.Text)
                { 
                    case "bitm":
                        DevComponents.DotNetBar.ControlContainerItem imageControl = new DevComponents.DotNetBar.ControlContainerItem();
                        imageControl.Stretch = true;
                        RawBar.Stretch = true;
                        bitmViewer.Bitmap = Map.Bitmaps[e.Node.Text];
                        imageControl.Control = bitmViewer;
                        RawBar.SubItems.Add(imageControl);
                        break;
                }

                txtTagPath.Enabled = true;
                txtTagClass.Enabled = true;
                cmdTagInfoSave.Enabled = true;
                cmdMetaExtract.Enabled = true;
                cmdMetaInject.Enabled = true;
                cmdMetaRemove.Enabled = true;
                cmdMetaDuplicate.Enabled = true;
            }
            else
            {
                txtTagOffset.TextBox.Text = "";
                txtTagSize.TextBox.Text = "";
                txtTagPath.TextBox.Text = "";
                txtTagClass.TextBox.Text = "";
                txtTagPath.Enabled = false;
                txtTagClass.Enabled = false;
                cmdTagInfoSave.Enabled = false;
                cmdMetaExtract.Enabled = false;
                cmdMetaInject.Enabled = false;
                cmdMetaRemove.Enabled = false;
                cmdMetaDuplicate.Enabled = false;
            }

            TagsBar.Refresh();
        }

        private void cmdIndexSave_Click(object sender, EventArgs e)
        {
            try
            {
                StatusChanged("Writing Index.");
                Map.ReOpen();
                SaveIndex();
                Map.Flush();
                LoadIndex();
            }
            catch { throw; }
            finally
            {
                Map.Flush();
                Map.Close();
                StatusChanged("Ready.");
            }
        }

        #region Index
        public void LoadIndex()
        {
            txtGlobalsID.TextBox.Text = Map.Index.GlobalsID.ToString();
            txtPrimaryMagic.TextBox.Text = Map.Index.PrimaryMagic.ToString();
            txtPrimaryMagicConstant.TextBox.Text = Map.Index.PrimaryMagicConstant.ToString();
            txtScenarioID.TextBox.Text = Map.Index.ScnrID.ToString();
            txtTagInfoIndexOffset.TextBox.Text = Map.Index.TagInfoIndexOffset.ToString();
            txtTagInfoIndexPointer.TextBox.Text = Map.Index.TagInfoIndexPointer.ToString();
            txtTagCount.TextBox.Text = Map.Index.TagCount.ToString();
            txtTags.TextBox.Text = Map.Index.Tags;
            txtSecondaryMagic.TextBox.Text = Map.Index.SecondaryMagic.ToString();
            txtSecondaryMagicConstant.TextBox.Text = Map.Index.SecondaryMagicConstant.ToString();
        }

        public void SaveIndex()
        {
            Map.Index.GlobalsID = Convert.ToInt32(txtGlobalsID.TextBox.Text);
            Map.Index.PrimaryMagicConstant = Convert.ToInt32(txtPrimaryMagicConstant.TextBox.Text);
            Map.Index.ScnrID = Convert.ToInt32(txtScenarioID.TextBox.Text);
            Map.Index.TagInfoIndexPointer = Convert.ToInt32(txtTagInfoIndexPointer.TextBox.Text);
            Map.Index.TagCount = Convert.ToInt32(txtTagCount.TextBox.Text);
            Map.Index.Tags = txtTags.TextBox.Text;
            Map.Index.SecondaryMagicConstant = Convert.ToInt32(txtSecondaryMagicConstant.TextBox.Text);
        }
        #endregion

        #region Header
        public void LoadHeader()
        {
            txtHead.TextBox.Text = Map.Header.Head;
            txtVersion.TextBox.Text = Map.Header.Version.ToString();
            txtFileSize.TextBox.Text = Map.Header.Filesize.ToString();
            txtIndexOffset.TextBox.Text = Map.Header.IndexOffset.ToString();
            txtIndexSize.TextBox.Text = Map.Header.IndexSize.ToString();
            txtMetaStart.TextBox.Text = Map.Header.MetaStart.ToString();
            txtMetaSize.TextBox.Text = Map.Header.MetaSize.ToString();
            txtNonRawSize.TextBox.Text = Map.Header.NonRawSize.ToString();
            txtOrigin.TextBox.Text = Map.Header.Origin;
            txtBuildDate.TextBox.Text = Map.Header.BuildDate;
            cboMapType.SelectedIndex = Map.Header.MapTypeInt;
            txtStrangeFileStringsSize.TextBox.Text = Map.Header.StrangeFileStringsSize.ToString();
            txtStrangeFileStringsOffset.TextBox.Text = Map.Header.StrangeFileStringsOffset.ToString();
            txtStringIDs128Offset.TextBox.Text = Map.Header.StringIDs128Offset.ToString();
            txtStringIDCount.TextBox.Text = Map.Header.StringIDCount.ToString();
            txtStringIDsSize.TextBox.Text = Map.Header.StringIDsSize.ToString();
            txtStringIDsIndex.TextBox.Text = Map.Header.StringIDsIndex.ToString();
            txtStringIDsOffset.TextBox.Text = Map.Header.StringIDsOffset.ToString();
            txtInternalName.TextBox.Text = Map.Header.InternalName;
            txtScenarioName.TextBox.Text = Map.Header.ScenarioName;
            this.Text = Map.Header.ScenarioName;
            txtFileTableCount.TextBox.Text = Map.Header.FileTableCount.ToString();
            txtFileTableOffset.TextBox.Text = Map.Header.FileTableOffset.ToString();
            txtFileTableSize.TextBox.Text = Map.Header.FileTableSize.ToString();
            txtFileTableIndexOffset.TextBox.Text = Map.Header.FileTableIndexOffset.ToString();
            txtChecksum.TextBox.Text = Map.Header.Checksum.ToString();
            txtFoot.TextBox.Text = Map.Header.Foot;
        }

        public void SaveHeader()
        {
            Map.Header.Head = txtHead.TextBox.Text;
            Map.Header.Version = Convert.ToInt32(txtVersion.TextBox.Text);
            Map.Header.Filesize = Convert.ToInt32(txtFileSize.TextBox.Text);
            Map.Header.IndexOffset = Convert.ToInt32(txtIndexOffset.TextBox.Text);
            Map.Header.IndexSize = Convert.ToInt32(txtIndexSize.TextBox.Text);
            Map.Header.MetaSize = Convert.ToInt32(txtMetaSize.TextBox.Text);
            Map.Header.NonRawSize = Convert.ToInt32(txtNonRawSize.TextBox.Text);
            Map.Header.Origin = txtOrigin.TextBox.Text;
            Map.Header.BuildDate = txtBuildDate.TextBox.Text;
            Map.Header.MapTypeInt = cboMapType.SelectedIndex;
            Map.Header.StrangeFileStringsSize = Convert.ToInt32(txtStrangeFileStringsSize.TextBox.Text);
            Map.Header.StrangeFileStringsOffset = Convert.ToInt32(txtStrangeFileStringsOffset.TextBox.Text);
            Map.Header.StringIDs128Offset = Convert.ToInt32(txtStringIDs128Offset.TextBox.Text);
            Map.Header.StringIDCount = Convert.ToInt32(txtStringIDCount.TextBox.Text);
            Map.Header.StringIDsSize = Convert.ToInt32(txtStringIDsSize.TextBox.Text);
            Map.Header.StringIDsIndex = Convert.ToInt32(txtStringIDsIndex.TextBox.Text);
            Map.Header.StringIDsOffset = Convert.ToInt32(txtStringIDsOffset.TextBox.Text);
            Map.Header.InternalName = txtInternalName.TextBox.Text;
            Map.Header.ScenarioName = txtScenarioName.TextBox.Text;
            Map.Header.FileTableCount = Convert.ToInt32(txtFileTableCount.TextBox.Text);
            Map.Header.FileTableOffset = Convert.ToInt32(txtFileTableOffset.TextBox.Text);
            Map.Header.FileTableSize = Convert.ToInt32(txtFileTableSize.TextBox.Text);
            Map.Header.FileTableIndexOffset = Convert.ToInt32(txtFileTableIndexOffset.TextBox.Text);
            Map.Header.Checksum = Convert.ToInt32(txtChecksum.TextBox.Text);
            Map.Header.Foot = txtFoot.TextBox.Text;
        }
        #endregion

        #region Unicode
        public void LoadUnicode()
        {
            lstChinese.Items.AddRange(Map.Unicode.Chinese.ReadTable());
            lstDutch.Items.AddRange(Map.Unicode.Dutch.ReadTable());
            lstEnglish.Items.AddRange(Map.Unicode.English.ReadTable());
            lstFrench.Items.AddRange(Map.Unicode.French.ReadTable());
            lstItalian.Items.AddRange(Map.Unicode.Italian.ReadTable());
            lstJapanese.Items.AddRange(Map.Unicode.Japanese.ReadTable());
            lstKorean.Items.AddRange(Map.Unicode.Korean.ReadTable());
            lstPortuguese.Items.AddRange(Map.Unicode.Portuguese.ReadTable());
            lstSpanish.Items.AddRange(Map.Unicode.Spanish.ReadTable());
        }
        #endregion

        private void cmdHeaderSave_Click(object sender, EventArgs e)
        {
            try
            {
                StatusChanged("Writing Header.");
                Map.ReOpen();
                SaveHeader();
                LoadHeader();
            }
            catch { throw; }
            finally
            {
                Map.Flush();
                Map.Close();
                StatusChanged("Ready.");
            }
        }

        private void lstSIDs_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstSIDs.SelectedIndex == -1)
            {
                txtSIDIndex.TextBox.Text = lstSIDs.SelectedIndex.ToString();
                txtSIDName.TextBox.Text = "";
                txtSIDName.Enabled = false;
            }
            else
            {
                txtSIDIndex.TextBox.Text = lstSIDs.SelectedIndex.ToString();
                txtSIDName.TextBox.Text = Map.StringIDs[(ushort)lstSIDs.SelectedIndex].ToString();
                txtSIDName.Enabled = true;
            }
        }

        private void cmdSIDSave_Click(object sender, EventArgs e)
        {
            try
            {
                StatusChanged("Writing String ID.");
                Map.ReOpen();
                Map.StringIDs[(ushort)lstSIDs.SelectedIndex].Rename(txtSIDName.TextBox.Text);
                Map.StringIDs.WriteStringIDs();
                lstSIDs.Items[lstSIDs.SelectedIndex] = Map.StringIDs[(ushort)lstSIDs.SelectedIndex].ToString();
            }
            catch { throw; }
            finally
            {
                Map.Flush();
                Map.Close();
                StatusChanged("Ready.");
            }
        }

        private void lstPortuguese_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtPortugeseIndex.TextBox.Text = lstPortuguese.SelectedIndex.ToString();
        }

        private void lstChinese_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtChineseIndex.TextBox.Text = lstChinese.SelectedIndex.ToString();
        }

        private void lstKorean_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtKoreanIndex.TextBox.Text = lstKorean.SelectedIndex.ToString();
        }

        private void lstItalian_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtItalianIndex.TextBox.Text = lstItalian.SelectedIndex.ToString();
        }

        private void lstSpanish_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtSpanishIndex.TextBox.Text = lstSpanish.SelectedIndex.ToString();
        }

        private void lstFrench_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtFrenchIndex.TextBox.Text = lstFrench.SelectedIndex.ToString();
        }

        private void lstDutch_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtDutchIndex.TextBox.Text = lstDutch.SelectedIndex.ToString();
        }

        private void lstJapanese_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtJapaneseIndex.TextBox.Text = lstJapanese.SelectedIndex.ToString();
        }

        private void lstEnglish_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtEnglishIndex.TextBox.Text = lstEnglish.SelectedIndex.ToString();
        }

        private void cmdResign_Click(object sender, EventArgs e)
        {
            try
            {
                Map.ReOpen();
                Map.Resign();
            }
            catch { throw; }
            finally
            {
                Map.Flush();
                Map.Close();
                StatusChanged("Ready.");
            }
        }

        private void cmdTagInfoSave_Click(object sender, EventArgs e)
        {
            try
            {
                this.Enabled = false;
                string OldPath = trvTags.SelectedNode.Text;
                string NewPath = txtTagPath.TextBox.Text;
                string OldClass = trvTags.SelectedNode.Parent.Text;
                string NewClass = txtTagClass.TextBox.Text;
                Map.ReOpen();
                StatusChanged("Writing Tag Info.");
                Application.DoEvents();
                NewPath = Map.Tags.Rename(OldClass, OldPath, NewPath);
                Map.Tags.ReClass(OldClass, NewPath, NewClass);
                trvTags.SelectedNode.Parent.Nodes.Remove(trvTags.SelectedNode);
                trvTags.Nodes[NewClass].Nodes.Add(NewClass, NewPath);
            }
            catch { throw; }
            finally
            {
                Map.Flush();
                Map.Close();
                this.Enabled = true;
                StatusChanged("Ready.");
            }
        }

        private void cmdMetaExtract_Click(object sender, EventArgs e)
        {
            string Class = trvTags.SelectedNode.Parent.Text;
            string Path = trvTags.SelectedNode.Text;
            SaveFileDialog SFD = new SaveFileDialog();
            SFD.Filter = Class + "(*.)" + Class + "|*." + Class;
            SFD.AddExtension = true;
            SFD.Title = "Save Tag...";
            string[] filepath = Path.Split(new char[] { '\\' });
            SFD.FileName = filepath[filepath.Length - 1];

            if (SFD.ShowDialog() == DialogResult.OK)
            {
                FileStream file = new FileStream(SFD.FileName, FileMode.Create, FileAccess.Write);
                BinaryFormatter bf = new BinaryFormatter();
                Map.ReOpen();
                Stream mm = main.MainMenuMap();
                Stream s = main.SharedMap();
                Stream sps =  main.SharedMap();
                bf.Serialize(file, Map.Tags.ExtractTag(Class, Path, new BinaryReader(mm), new BinaryReader(s), new BinaryReader(sps)));
                mm.Close();
                s.Close();
                sps.Close();
                Map.Close();
                file.Flush();
                file.Close();
                MessageBox.Show("Done.", "Meta Extract", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void cmdMetaInject_Click(object sender, EventArgs e)
        {
            string Class = trvTags.SelectedNode.Parent.Text;
            string Path = trvTags.SelectedNode.Text;
            OpenFileDialog OFD = new OpenFileDialog();
            OFD.Filter = Class + "(*.)" + Class + "|*." + Class;
            OFD.Title = "Open Tag...";

            if (OFD.ShowDialog() == DialogResult.OK)
            {
                H2.DataTypes.TagContainer tagCon;
                FileStream file = new FileStream(OFD.FileName, FileMode.Open, FileAccess.Read);
                BinaryFormatter bf = new BinaryFormatter();
                tagCon = (H2.DataTypes.TagContainer)bf.Deserialize(file);
                file.Close();

                H2.Sections.TagInfo ti = Map.Tags[Class, Path];

                if (Map.Tags.GetSize(tagCon.Tag, true) <= ti.Size)
                {
                    Map.ReOpen();
                    Map.Position = ti.Offset;
                    int EofMeta = ti.Offset + Map.Tags.GetSize(tagCon.Tag, false);
                    Map.Write(tagCon.Tag.GetType(), tagCon.Tag, Map.Index.SecondaryMagic, ref EofMeta);
                    Map.Close();

                    MessageBox.Show("Done.", "Meta Inject", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                    MessageBox.Show("The Tag You Have Choosen Is Larger Than The Origonal Meta And Cannot Be Injected. The Map Has Not Been Altered.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void cmdMetaRemove_Click(object sender, EventArgs e)
        {
            string Class = trvTags.SelectedNode.Parent.Text;
            string Path = trvTags.SelectedNode.Text;
            if (MessageBox.Show("Removing A Tag Could Likely Cause Your Map To Break. Are You Sure You Want To Remove " + Class + " - " + Path + "?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {

            }
        }

        private void cmdAddTagFromFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog OFD = new OpenFileDialog();
            OFD.Filter = "All Files(*.*)|*.*";
            OFD.Title = "Open Tag...";

            if (OFD.ShowDialog() == DialogResult.OK)
            {
                TagAddOptionDialogue TAOD = new TagAddOptionDialogue();
                string[] strs = OFD.FileName.Split(new char[] { '.' });
                string Class = strs[1];
                string Path = strs[0];
                if (Path.Contains(MySettings.Default.TagsRootDir))
                    Path = Path.Remove(0, MySettings.Default.TagsRootDir.Length);
                TAOD.TagName = Path;
                if (TAOD.ShowDialog() == DialogResult.OK)
                {
                    this.Enabled = false;
                    Path = TAOD.TagName;
                    H2.DataTypes.TagContainer TagCon;
                    FileStream file = new FileStream(OFD.FileName, FileMode.Open, FileAccess.Read);
                    BinaryFormatter bf = new BinaryFormatter();
                    TagCon = (H2.DataTypes.TagContainer)bf.Deserialize(file);
                    file.Close();

                    Map.ReOpen();
                    Map.Tags.Add(TagCon, Class, Path);
                    Map.Flush();
                    Map.Close();

                    if (trvTags.Nodes[Class] == null)
                        trvTags.Nodes.Add(Class, Class);
                    trvTags.Nodes[Class].Nodes.Add(Class, Path);

                    MessageBox.Show("Done.", "Meta Inject", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    this.Enabled = true;
                }
            }
        }

        private void cmdExtractAllTags_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog FBD = new FolderBrowserDialog();
            FBD.Description = "Select Root Folder...";
            FBD.SelectedPath = MySettings.Default.TagsRootDir;
            if (FBD.ShowDialog() == DialogResult.OK)
            {
                this.Enabled = false;
                H2.Sections.Tags.TagTable tt = Map.Tags.GetTagTable();
                probar.Maximum = tt.Count;
                probar.Value = 0;
                for (int i = 0; i < tt.Count; i++)
                {
                    FileStream file = new FileStream(FBD.SelectedPath + "\\" + tt[i].Path + "." + tt[i].Class, FileMode.Create, FileAccess.Write);
                    BinaryFormatter bf = new BinaryFormatter();
                    Map.ReOpen();
                    bf.Serialize(file, Map.Tags.LoadTag(tt[i].Class, tt[i].Path));
                    Map.Close();
                    file.Flush();
                    file.Close();
                    probar.Value++;
                }
                probar.Value = 0;
                
                MessageBox.Show("Done.", "Meta Extract", MessageBoxButtons.OK, MessageBoxIcon.Information);
                this.Enabled = true;
            }
        }

        private void cmdMetaDuplicate_Click(object sender, EventArgs e)
        {
            TagAddOptionDialogue TAOD = new TagAddOptionDialogue();
            string Path = trvTags.SelectedNode.Text;
            string Class = trvTags.SelectedNode.Parent.Text;
            TAOD.TagName = trvTags.SelectedNode.Text + "NEW";
            if (TAOD.ShowDialog() == DialogResult.OK)
            {
                this.Enabled = false;
                Map.ReOpen();
                Map.Tags.Duplicate(Class, Path, TAOD.TagName);
                Map.Flush();
                Map.Close();

                trvTags.Nodes[Class].Nodes.Add(Class, TAOD.TagName);

                MessageBox.Show("Done.", "Meta Inject", MessageBoxButtons.OK, MessageBoxIcon.Information);
                this.Enabled = true;
            }
        }
    }
}